package ezxpns;

import java.io.*;
import javax.swing.event.*;
import ezxpns.types.*;
import ezxpns.util.*;

public class Manager implements Wrappable<Manager.View,CommandGroup>
{
	private boolean acquired;
	private String text;
	private Bound<VLong> selection;
	public Manager(InputStream input) throws Exception
	{
		text="";
		if( input!=null )
		{
			BufferedReader in=new BufferedReader(new InputStreamReader(input,"utf-8"));
			while(true)
			{
				String i=in.readLine();
				if( i==null ) break;
				text+=i+System.getProperty("line.separator");
			}
		}
		acquired=false;
	}
	public void export(OutputStream output) throws Exception
	{
		BufferedWriter out=new BufferedWriter(new OutputStreamWriter(output,"utf-8"));
		out.write(text);
		out.flush();
	}
	private class ManagerKey implements Key<CommandGroup>
	{
		@SuppressWarnings("unchecked")
		public CommandGroup exec(Command<?> command)
		{
			// All actions are undoable except for select() and export() which do not affect undo history
			String action=command.getAction();
			Object data=command.getData();
			try
			{
				if( action.matches("text select") )
				{
					selection=((Bound<VLong>)data).copy();
					return new CommandGroup();
				}
				if( action.matches("text edit") )
				{
					Pointer<UndoableEditEvent> edit=(Pointer<UndoableEditEvent>)data;
					if( edit.value().getEdit().canRedo() )
					{
						edit.value().getEdit().redo();
						return null;
					}
					CommandGroup undoGroup=new CommandGroup();
					undoGroup.add(new Command<Pointer<UndoableEditEvent>>("text undo",edit));
					undoGroup.add(new Command<Bound<VLong>>("text select",selection.copy()));
					return undoGroup;
				}
				if( action.matches("text undo") )
				{
					((Pointer<UndoableEditEvent>)data).value().getEdit().undo();
					return null;
				}
				if( action.matches("text set") )
				{
					text=((VString)data).value();
					return new CommandGroup();
				}
			}
			catch(ClassCastException e)
			{
				throw new AssertionError("Don't trick me with invalid data for action \""+action+"\"!");
			}
			throw new AssertionError("Invalid action \""+action+"\"!");
		}
	}
	public Key<CommandGroup> acquire()
	{
		if( acquired ) return null;
		acquired=true;
		return new ManagerKey();
	}
	public void release()
	{	// will not be used in Manager
	}
	public class View
	{
		public void export(OutputStream output) throws Exception
		{ Manager.this.export(output); }
		public String getText()
		{ return Manager.this.text; }
		public Bound<VLong> getSelection()
		{ return Manager.this.selection; }
	}
	final private View view=new View();
	public View getView()
	{
		return view;
	}
}
